package com.chuangke.file.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chuangke.admin.data.builder.UserDataBuilder;
import com.chuangke.admin.entity.SysUser;
import com.chuangke.admin.service.SysUserService;
import com.chuangke.common.constant.Masks;
import com.chuangke.common.data.builder.DataBuildConfig;
import com.chuangke.common.data.builder.DataBuilder;
import com.chuangke.common.db.page.CkPageQuery;
import com.chuangke.common.exception.ChuangkeException;
import com.chuangke.file.dao.FileInfoMapper;
import com.chuangke.file.dao.FileVersionMapper;
import com.chuangke.file.model.FileAnalyseResponse;
import com.chuangke.file.model.FileDbank;
import com.chuangke.file.model.FileDownloadHistory;
import com.chuangke.file.model.FileInfo;
import com.chuangke.file.model.FileInfoAffix;
import com.chuangke.file.model.FileInfoVersion;
import com.chuangke.file.model.SysFilePermission;
import com.chuangke.file.model.SysFileShare;
import com.chuangke.file.service.FileDbankService;
import com.chuangke.file.service.FileDownloadHistoryService;
import com.chuangke.file.service.FileInfoAffixService;
import com.chuangke.file.service.FileQueryService;
import com.chuangke.file.service.SysFilePermissionService;
import com.chuangke.file.service.SysFileShareService;
import com.chuangke.file.util.DateUtil;
import com.chuangke.system.entity.SysComment;
import com.chuangke.system.entity.SysFocus;
import com.chuangke.system.service.SysCommentService;
import com.chuangke.system.service.SysFocusService;

import cn.hutool.core.util.StrUtil;

@Service
public class FileQueryServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements FileQueryService {

	@Autowired
	private FileInfoMapper fileMapper;
	@Autowired
	private FileVersionMapper fileVersionMapper;
	@Autowired
	private SysFileShareService sysFileShareService;
	@Autowired
	private FileInfoAffixService fileInfoAffixService;
	@Autowired
	private SysFocusService sysFocusService;
	@Autowired
	private SysCommentService sysCommentService;
	@Autowired
	private SysFilePermissionService sysFilePermissionService;
	@Autowired
	private FileDbankService fileDbankService ;
	@Autowired
	private SysUserService sysUserService;
	@Autowired
	private FileDownloadHistoryService fileDownloadHistoryService;
	
	/**
	 * 参数:分页（current,size）,name,dbankId
	 */
	@Override
	public IPage<FileInfo> query(CkPageQuery pageQuery) {
		String name = pageQuery.get("name").toString();
		name = name == null ? "" : name;
		String dbankId = (String) pageQuery.get("dbankId");
		if (StrUtil.isBlank(dbankId)) {
			throw new ChuangkeException("缺少参数dbankId");
		}
		return fileMapper.selectPage(pageQuery.getPage(),
				new QueryWrapper<FileInfo>().lambda().eq(FileInfo::getDelFlag, Masks.BOOL_NO)
						.eq(FileInfo::getDbankId, dbankId).like(FileInfo::getName, name));
	}

	/*
	 * 查询附件列表
	 */
	@Override
	public List<FileInfo> listFiles(List<String> fileIds) {
		if (fileIds == null || fileIds.isEmpty()) {
			return null;
		}

		return fileMapper.selectBatchIds(fileIds);
	}

	@Override
	public List<FileInfo> listFiles(String parentId, String dbankId, String delFlag, String fileType, String order) {
		QueryWrapper<FileInfo> wrapper = new QueryWrapper<>();
		if (!Masks.BOOL_YES.equals(delFlag)) {
			wrapper.lambda().eq(true, FileInfo::getParentId, parentId);
		}
		if (!Masks.ALL.equals(fileType)) {
			wrapper.lambda().eq(true, FileInfo::getType, FileInfo.TYPE_DIR);
		}
		wrapper.lambda().eq(true, FileInfo::getDbankId, dbankId).eq(FileInfo::getDelFlag, delFlag);
		wrapper.lambda().orderByAsc(FileInfo::getType);
		if (!StrUtil.isBlank(order)) {
			if ("name".equals(order) || "size".equals(order)) {
				wrapper.orderByDesc(order);
			}
			if ("updatedAt".equals(order)) {
				wrapper.lambda().orderByDesc(FileInfo::getUpdatedAt);
			}
		} else {
			wrapper.orderByAsc("name");
		}

		List<FileInfo> fileList = fileMapper.selectList(wrapper);
		fileList.forEach(file-> file.setDbankName(fileDbankService.loadDbankById(file.getDbankId()).getName()));

		DataBuilder.of(fileList).appendBuilder(new UserDataBuilder(), new DataBuildConfig("createdBy", "createdBy"),
				new DataBuildConfig("updatedBy", "updatedBy")).build();
		return fileList;
	}

	@Override
	public List<FileInfo> listShareFiles(String dbankId, String userId, String order) {
		List<SysFilePermission> permissionList = sysFilePermissionService.listAuthFiles(dbankId, userId);

		if (CollectionUtils.isEmpty(permissionList)) {
			return new ArrayList<>();
		}

		Map<String, List<SysFilePermission>> filePermissionMap = permissionList.stream()
				.collect(Collectors.groupingBy(SysFilePermission::getFileId));

		QueryWrapper<FileInfo> wrapper = new QueryWrapper<>();
		wrapper.lambda().in(FileInfo::getId,
				permissionList.stream().map(SysFilePermission::getFileId).collect(Collectors.toList()));
		wrapper.lambda().eq(true, FileInfo::getDbankId, dbankId).eq(FileInfo::getDelFlag, Masks.BOOL_NO);
		wrapper.lambda().orderByAsc(FileInfo::getType);
		if (!StrUtil.isBlank(order)) {
			if ("name".equals(order) || "size".equals(order)) {
				wrapper.orderByDesc(order);
			}
			if ("updatedAt".equals(order)) {
				wrapper.lambda().orderByDesc(FileInfo::getUpdatedAt);
			}
		} else {
			wrapper.orderByAsc("name");
		}

		List<FileInfo> fileList = fileMapper.selectList(wrapper);

		fileList.forEach(file -> {
			List<SysFilePermission> pList = filePermissionMap.get(file.getId());
			pList.forEach(p -> {
				if (file.getPermission() == null) {
					file.setPermission(p);
				} else if (file.getPermission().getAuthRole().compareTo(p.getAuthRole()) > 0) {
					file.setPermission(p);
				}
			});
		});

		DataBuilder.of(fileList).appendBuilder(new UserDataBuilder(), new DataBuildConfig("createdBy", "createdBy"),
				new DataBuildConfig("updatedBy", "updatedBy")).build();
		return fileList;
	}

	@Override
	public List<FileInfoVersion> listHistory(String fileId) {
		List<FileInfoVersion> fileList = fileVersionMapper
				.selectList(new QueryWrapper<FileInfoVersion>().lambda().eq(FileInfoVersion::getId, fileId));
		DataBuilder.of(fileList).appendBuilder(new UserDataBuilder(), new DataBuildConfig("createdBy", "createdBy"),
				new DataBuildConfig("updatedBy", "updatedBy")).build();
		return fileList;
	}

	@Override
	public FileInfo load(String id) {
		FileInfo fileInfo = fileMapper.selectById(id);
		if (fileInfo == null) {
			return null;
		}

		if (FileInfo.TYPE_FILE.equals(fileInfo.getType())) {
			List<FileInfoAffix> affixList = fileInfoAffixService
					.list(new QueryWrapper<FileInfoAffix>().lambda().eq(FileInfoAffix::getFileId, id));
			fileInfo.setAffixList(affixList);
		}

		return fileInfo;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public IPage<Map<String, Object>> pageShare(CkPageQuery pageQuery) {
		pageQuery.put("type", SysFocus.PROP_TYPE_FILE);
		IPage sharePage = sysFileShareService.page(pageQuery);

		if (sharePage.getRecords() == null || sharePage.getRecords().isEmpty()) {
			return sharePage;
		}

		List<String> fileIds = (List<String>) sharePage.getRecords().stream().map(f -> ((SysFileShare) f).getFileId())
				.collect(Collectors.toList());
		Map<String, FileInfo> files = this.listByIds(fileIds).stream()
				.collect(Collectors.toMap(FileInfo::getId, a -> a));
		List<Map<String, Object>> datas = BeanUtils.beansToMaps(sharePage.getRecords());

		List<Map<String, Object>> records = new ArrayList<>(datas.size());
		datas.forEach(data -> {
			Map<String, Object> record = new HashMap<>();
			FileInfo file = files.get(data.get("fileId"));
			if (file != null) {
				record.putAll(BeanUtils.beanToMap(file));
			}
			// 顺序不能换，要将分享记录的id传到前台，用于取消分享
			records.add(record);
			record.putAll(data);
		});
		sharePage.setRecords(records);
		return sharePage;
	}

	@Override
	public List<FileInfo> getChildrenFileIds(List<String> fileIds) {
		List<FileInfo> files = listDeepFiles(fileIds);
		return files.stream().filter(file -> FileInfo.TYPE_FILE.equals(file.getType())).collect(Collectors.toList());
	}

	@Override
	public List<FileInfo> listDeepFiles(List<String> fileIds) {
		Map<String, FileInfo> fileMap = new HashMap<>();
		Map<String, String> fileNameMap = new HashMap<>();
		List<FileInfo> fileList = findFileAndChildren(fileIds);
		deepFindChilrenFiles(fileList, fileMap, fileNameMap);

		return new ArrayList<>(fileMap.values());
	}

	private void deepFindChilrenFiles(List<FileInfo> fileList, Map<String, FileInfo> fileMap,
			Map<String, String> fileNameMap) {
		if (CollectionUtils.isEmpty(fileList)) {
			return;
		}

		fileMap.putAll(fileList.stream().collect(Collectors.toMap(FileInfo::getId, a -> a)));

		List<String> fileChildrenIds = new ArrayList<>();
		fileList.forEach(file -> {
			FileInfo parent = fileMap.get(file.getParentId());
			String name = parent == null ? file.getName() : parent.getName() + "/" + file.getName();
			fileNameMap.put(file.getId(), name);
			if (parent != null) {
				fileChildrenIds.add(file.getId());
			}
		});
		fileList = findChildrenFile(fileChildrenIds);
		deepFindChilrenFiles(fileList, fileMap, fileNameMap);
	}

	private List<FileInfo> findFileAndChildren(List<String> fileIds) {
		if (CollectionUtils.isEmpty(fileIds)) {
			return new ArrayList<>();
		}
		return fileMapper.selectList(new QueryWrapper<FileInfo>().lambda().in(FileInfo::getId, fileIds).or()
				.in(FileInfo::getParentId, fileIds));
	}

	private List<FileInfo> findChildrenFile(List<String> fileIds) {
		if (CollectionUtils.isEmpty(fileIds)) {
			return new ArrayList<>();
		}
		return fileMapper.selectList(new QueryWrapper<FileInfo>().lambda().in(FileInfo::getParentId, fileIds));
	}

	@Override
	public List<FileInfo> listAllParentFiles(String fileId) {
		List<FileInfo> parentFiles = new ArrayList<>();
		FileInfo parent = getParentFile(fileId);
		while (parent != null && !StrUtil.isBlank(parent.getParentId()) && !"0".equals(parent.getParentId())) {
			parentFiles.add(parent);
			parent = getParentFile(parent.getParentId());
		}
		return parentFiles;
	}

	private FileInfo getParentFile(String fileId) {
		if (StrUtil.isBlank(fileId)) {
			return null;
		}
		return fileMapper.selectOne(new QueryWrapper<FileInfo>().lambda().eq(FileInfo::getId, fileId));
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public IPage pageFocus(CkPageQuery pageQuery) {
		pageQuery.put("type", SysFocus.PROP_TYPE_FILE);
		IPage focusPage = sysFocusService.page(pageQuery);

		if (focusPage.getRecords() == null || focusPage.getRecords().isEmpty()) {
			return focusPage;
		}

		List<String> fileIds = (List<String>) focusPage.getRecords().stream().map(f -> ((SysFocus) f).getPropId())
				.collect(Collectors.toList());
		Map<String, FileInfo> files = this.listByIds(fileIds).stream()
				.collect(Collectors.toMap(FileInfo::getId, a -> a));
		List<Map<String, Object>> datas = BeanUtils.beansToMaps(focusPage.getRecords());

		List<Map<String, Object>> records = new ArrayList<>(datas.size());
		datas.forEach(data -> {
            Map<String, Object> record = new HashMap<>(data);
			FileInfo file = files.get(data.get("propId"));
			if (file != null) {
				Map<String, SysUser> userMap = sysUserService.findMap() ;
				record.putAll(BeanUtils.beanToMap(file));
				FileDbank dbank = fileDbankService.loadDbankById(file.getDbankId()) ;
				record.put("dbankName", dbank.getName()) ;
				record.put("dbankType", dbank.getType()) ;
				record.put("updatedBy", userMap.get(file.getUpdatedBy()) != null ? userMap.get(file.getUpdatedBy()).getNickName():file.getUpdatedBy() ) ;
				record.put("createdBy", userMap.get(file.getCreatedBy()) != null ? userMap.get(file.getCreatedBy()).getNickName():file.getCreatedBy() ) ;
			}
			records.add(record);
		});
		focusPage.setRecords(records);
		return focusPage;
	}

	@Override
	public List<SysComment> listComments(String id) {
		List<SysComment> commentList = sysCommentService.getListByTopId(id, SysComment.TOPIC_TYPE_FILE);
		DataBuilder.of(commentList)
				.appendBuilder(new UserDataBuilder(), new DataBuildConfig("commentBy", "commentByName")).build();
		return commentList;
	}

	@Override
	public IPage<FileInfo> pagePublish(CkPageQuery pageQuery) {
		String dbankId=(String) pageQuery.get("dbankId");
		String category = (String) pageQuery.get("category");
		QueryWrapper<FileInfo> querry=new QueryWrapper<>();
		if(dbankId!=null&& !dbankId.isEmpty()) {
			querry.lambda().eq(FileInfo::getDbankId, dbankId);
		}
		if(!StrUtil.isBlank(category) && !Masks.ALL.equals(category)) {
			if(Masks.OTHER.equals(category)) {
				querry.lambda().isNull(FileInfo::getCategory);
			}else {
				querry.lambda().eq(FileInfo::getCategory, category);
			}
		}
		querry.lambda().eq(FileInfo::getIsPublish, Masks.BOOL_YES).orderByAsc(FileInfo::getUpdatedAt);
        return fileMapper.selectPage(pageQuery.getPage(), querry) ;
	}

	@Override
	public IPage<FileInfo> pageTopPublish(CkPageQuery pageQuery) {
		String dbankId=(String) pageQuery.get("dbankId");
		QueryWrapper<FileInfo> querry=new QueryWrapper<>();
		if(dbankId!=null&& !dbankId.isEmpty()) {
			querry.lambda().eq(FileInfo::getDbankId, dbankId);
		}
		querry.lambda().eq(FileInfo::getIsPublish, Masks.BOOL_YES).orderByAsc(FileInfo::getDownloadCount);
		return fileMapper.selectPage(pageQuery.getPage(), querry) ;
	}

	@Override
	public List<FileInfo> list(List<String> ids) {
		return this.listByIds(ids);
	}

	@Override
	public FileInfo find(String id) {
		if(id==null || id.isEmpty()) {
			return null ;
		}
		return this.getById(id) ;
	}

	@Override
	public FileAnalyseResponse analyse(String dbankId) {
		List<FileInfo> fileList=fileMapper.selectList(new QueryWrapper<FileInfo>().lambda().eq(FileInfo::getDbankId, dbankId));
		if(fileList==null) fileList=new ArrayList<>();
		//顶部内容获取
		FileAnalyseResponse result=new FileAnalyseResponse();
		result.setTotalFile(fileList.size());
		List<FileInfo> weekList=fileList.stream().filter(item->item.getCreatedAt().getTime()>DateUtil.getLastWeekTime()).collect(Collectors.toList());
		result.setWeekAddFile(weekList==null?0:weekList.size());
		List<FileInfo> monthList=fileList.stream().filter(item->item.getCreatedAt().getTime()>DateUtil.getLastMonthTime()).collect(Collectors.toList());
		result.setMonthAddFile(monthList==null?0:monthList.size());
		List<FileInfo> yearList=fileList.stream().filter(item->item.getCreatedAt().getTime()>DateUtil.getLastYearTime()).collect(Collectors.toList());
		result.setYearAddFile(yearList==null?0:yearList.size());
		//文档类别图(doc,docx,xls,xlsx,ppt,pptx,txt,pdf,其他)
		List<Integer> typeFileList=new ArrayList<>();
		List<FileInfo> docList=fileList.stream().filter(item->item.getSuffix()!=null&& "docx".contains(item.getSuffix().toLowerCase())).collect(Collectors.toList());
		typeFileList.add(docList==null?0:docList.size());
		List<FileInfo> pptList=fileList.stream().filter(item->item.getSuffix()!=null&& "pptx".contains(item.getSuffix().toLowerCase())).collect(Collectors.toList());
		typeFileList.add(pptList==null?0:pptList.size());
		List<FileInfo> txtList=fileList.stream().filter(item->item.getSuffix()!=null&& "txt".contains(item.getSuffix().toLowerCase())).collect(Collectors.toList());
		typeFileList.add(txtList==null?0:txtList.size());
		List<FileInfo> pdfList=fileList.stream().filter(item->item.getSuffix()!=null&& "pdf".contains(item.getSuffix().toLowerCase())).collect(Collectors.toList());
		typeFileList.add(pdfList==null?0:pdfList.size());
		List<FileInfo> xlsList=fileList.stream().filter(item->item.getSuffix()!=null&& "xlsx".contains(item.getSuffix().toLowerCase())).collect(Collectors.toList());
		typeFileList.add(xlsList==null?0:xlsList.size());
		typeFileList.add(fileList.size()-typeFileList.stream().reduce(Integer::sum).orElse(0));
		result.setTypeFileCount(typeFileList);
		//下载
		QueryWrapper<FileDownloadHistory> downQueryWrapper=new QueryWrapper<>();
		downQueryWrapper.select("count(id) as downCount,left(download_at,10) as downloadAt");
		downQueryWrapper.lambda().exists("select 1 from file_info where file_download_history.file_id=file_info.id and file_info.dbank_id="+dbankId);
		downQueryWrapper.lambda().gt(FileDownloadHistory::getDownloadAt, DateUtil.getLastMonthDate());
		downQueryWrapper.groupBy("downloadAt");
		List<FileDownloadHistory> downloadList=fileDownloadHistoryService.list(downQueryWrapper);
		result.setDownFileList(downloadList);
		//上传
		QueryWrapper<FileInfo> uploadQueryWrapper=new QueryWrapper<>();
		uploadQueryWrapper.select("count(id) as uploadCount,left(created_at,10) as createdAt");
		uploadQueryWrapper.lambda().eq(FileInfo::getDbankId, dbankId).gt(FileInfo::getCreatedAt, DateUtil.getLastMonthDate());
		uploadQueryWrapper.groupBy("createdAt");
		List<FileInfo> uploadList=fileMapper.selectList(uploadQueryWrapper);
		result.setAddFileList(uploadList);
		return result;
	}

}
